/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package commandhandlers;

import input.IRCCommand;
import interfaces.CommandHandler;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import main.Bot;
import main.CommonMethods;
import main.Constants;
import main.Main;
import main.UserCentral;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import output.IRCOutput;
import tools.InputType;
import tools.StringTools;
import tools.UtopiaTime;
import utopiaintelpackage.database.KDtoDB;
import utopiaintelpackage.kd.KD;
import utopiaintelpackage.survey.Survey;
import botobjects.Aid;
import botobjects.Attendance;
import botobjects.Build;
import botobjects.Building;
import botobjects.ClaimedTarget;
import botobjects.Event;
import botobjects.Nap;
import botobjects.Order;
import botobjects.Province;
import botobjects.Readiness;
import database.DBConnectionFactory;
import exceptions.UtoDateException;

/**
 * This class takes care of functions related to the KD
 * 
 * 
 */
public class KDHandler extends CommandHandler {
   private static KDHandler INSTANCE = null;

   /**
    * Updates information about what the user has done. Such as when he/she last checked the aid list etc.
    * 
    * @param nick
    * @param type
    */
   public static void addUserCheck(final String nick, final String type) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM idle, nickname WHERE idle.mainnick = nickname.mainnick AND nickname.name = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			String mainNick = rs.getString("idle.mainnick");
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE idle SET " + "last" + type + "check = ? WHERE mainnick = ?");
			ps.setTimestamp(1, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setString(2, mainNick);
			ps.executeUpdate();
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM nickname WHERE name = ?");
			ps.setString(1, nick);
			rs = ps.executeQuery();

			if (rs.next()) {
			   String mainNick = rs.getString("mainnick");

			   try {
				  ps.close();
			   } catch (final Exception e) {
			   }

			   ps = DBConnectionFactory.getConnectionHandler().getConnection()
					 .prepareStatement("INSERT into idle VALUES(?,?,?,?,?,?,?,?)");
			   ps.setString(1, mainNick);
			   ps.setTimestamp(2, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(3, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(4, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(5, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(6, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(7, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.setTimestamp(8, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			   ps.executeUpdate();
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Removes and Aid request based on it's position in the aid list
    * 
    * @param no
    * @return
    */
   private static String delAid(final int no) {
	  String out = "";
	  Statement stmt = null;
	  ResultSet rs = null;
	  try {
		 stmt = DBConnectionFactory.getConnectionHandler().getConnection()
			   .createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
		 String query = "SELECT * FROM aid ORDER BY requesttime DESC";
		 rs = stmt.executeQuery(query);

		 int i = 1;
		 while (rs.next()) {
			if (i == no) {
			   rs.deleteRow();
			   out = "Aid request deleted";
			   break;
			}
			++i;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			stmt.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the amount of active aid requests
    * 
    * @return
    */
   public static int getAmountOfAidRequests() {
	  return Aid.getAidList().size();
   }

   /**
    * Returns the total amount of scheduled events
    * 
    * @return
    */
   public static int getAmountOfEvents() {
	  int out = 0;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM event WHERE eventtype = false");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			++out;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public static final KDHandler getInstance() {
	  if (INSTANCE == null) {
		 INSTANCE = new KDHandler();
	  }
	  return INSTANCE;
   }

   /**
    * Returns the amount of aid requests that have been added since the user last checked
    * 
    * @param nick
    * @return
    */
   public static int getNewAidAmount(final String nick) {
	  int out = 0;
	  PreparedStatement ps = null;
	  ResultSet rs = null;

	  Long lastCheck = getUserCheck(nick, "aid");
	  if (lastCheck == null)
		 return 0;

	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM aid");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (rs.getTimestamp("requesttime").getTime() > lastCheck) {
			   ++out;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Checks if a build has been added since the user last checked
    * 
    * @param nick
    * @return
    */
   public static boolean getNewBuildCheck(final String nick, final String racepers) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;

	  Long lastCheck = getUserCheck(nick, "build");
	  if (lastCheck == null)
		 return false;

	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM build WHERE racepers = ? OR racepers = ?");
		 ps.setString(1, racepers.substring(0, racepers.indexOf(' ')));
		 ps.setString(2, racepers);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			if (rs.getTimestamp("settime").getTime() > lastCheck) {
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the amount of events that have been added since the user last checked
    * 
    * @param nick
    * @return
    */
   public static int getNewEventsAmount(final String nick) {
	  int out = 0;
	  PreparedStatement ps = null;
	  ResultSet rs = null;

	  Long lastCheck = getUserCheck(nick, "events");
	  if (lastCheck == null)
		 return 0;

	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM event WHERE eventtype = false");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (rs.getTimestamp("settime").getTime() > lastCheck) {
			   ++out;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the amount of naps that have been added since the user last checked
    * 
    * @param nick
    * @return
    */
   public static int getNewNapsAmount(final String nick) {
	  int out = 0;
	  PreparedStatement ps = null;
	  ResultSet rs = null;

	  Long lastCheck = getUserCheck(nick, "naps");
	  if (lastCheck == null)
		 return 0;

	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM nap");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (rs.getTimestamp("settime").getTime() > lastCheck) {
			   ++out;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the amount of orders that have been added since the user last checked
    * 
    * @param nick
    * @return
    */
   public static int getNewOrdersAmount(final String nick) {
	  return listOrders(nick, true, false).size() - 1;
   }

   /**
    * Checks if a wave has been scheduled since the user last checked
    * 
    * @param nick
    * @return
    */
   public static boolean getNewWaveCheck(final String nick) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;

	  Long lastCheck = getUserCheck(nick, "wave");
	  if (lastCheck == null)
		 return false;

	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM event WHERE eventtype = true");
		 rs = ps.executeQuery();

		 if (rs.next()) {
			if (rs.getTimestamp("settime").getTime() > lastCheck) {
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the id of an order based on its position in the orders list
    * 
    * @param no
    * @return
    */
   public static int getOrderID(final Integer no) {
	  int out = 0;
	  if (no < 1)
		 return out;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM orders ORDER BY category, settime DESC");
		 rs = ps.executeQuery();

		 int counter = 1;
		 while (rs.next()) {
			if (no == counter) {
			   out = rs.getInt("id");
			}
			++counter;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Announces any events that are scheduled for the supplied uto date and then removes the expired events
    * 
    * @param utdate
    */
   public static void getScheduledEvents(final String utdate) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 UtopiaTime ut = new UtopiaTime(utdate);
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM event WHERE " + "eventtime <= ?");
		 ps.setTimestamp(1, new Timestamp(ut.getTime()));
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (rs.getTimestamp("eventtime").getTime() == ut.getTime()) {
			   Bot.getInstance().sendNotice(Main.getBotSettings().getMainChannel(),
					 "Get off your asses! " + (rs.getBoolean("eventtype") ? "Wave time!" : rs.getString("description")));
			   Bot.getInstance().sendMessage(
					 Main.getBotSettings().getMainChannel(),
					 Colors.RED + "Get off your asses! "
						   + (rs.getBoolean("eventtype") ? "Wave time!" : rs.getString("description")));

			   slapEvent("attending", rs.getString("description"), Main.getBotSettings().getMainChannel());
			   new Thread() {
				  @Override
				  public void run() {
					 CommonMethods.doSMSNotification("", 1, "");
				  }
			   }.start();
			}
		 }
		 removeOldEvents();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } catch (UtoDateException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Returns the show status for a kd. Should it be showed on the website or not?
    * 
    * @param kd
    * @return
    */
   public static boolean getShowKD(final String kd) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kd WHERE loc = ?");
		 ps.setString(1, kd);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			out = rs.getBoolean("showkd");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the time (represented by a Long) the user last checked the specified type of item
    * 
    * @param nick
    * @param type
    * @return
    */
   public static Long getUserCheck(final String nick, final String type) {
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  Long out = 0L;
	  try {
		 ps = DBConnectionFactory
			   .getConnectionHandler()
			   .getConnection()
			   .prepareStatement(
					 "SELECT last" + type
						   + "check FROM idle, nickname WHERE idle.mainnick = nickname.mainnick AND nickname.name = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			out = rs.getTimestamp("last" + type + "check").getTime();
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Checks whether a wave is currently scheduled
    * 
    * @return
    */
   public static boolean isWaveScheduled() {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM event WHERE eventtype = true");
		 rs = ps.executeQuery();

		 out = rs.next();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public static final KDHandler newInstance() {
	  INSTANCE = null;
	  return getInstance();
   }

   /**
    * Registers an aid package and updated the aid list accordingly
    * 
    * @param food
    * @param gold
    * @param runes
    * @param soldiers
    * @param prov
    * @return
    */
   public static List<String> registerAidPackage(final int food, final int gold, final int runes, final int soldiers,
		 final String prov) {
	  List<String> out = new LinkedList<String>();
	  final List<Aid> toDelete = new LinkedList<Aid>();
	  final List<Aid> aidList = Aid.getAidList();
	  for (final Aid a : aidList) {
		 if (a.getProvname().equals(prov)) {
			int before = a.getAmount();
			if (a.getResource().equals("food")) {
			   a.setAmount(a.getAmount() - food);
			} else if (a.getResource().equals("gc")) {
			   a.setAmount(a.getAmount() - gold);
			} else if (a.getResource().equals("runes")) {
			   a.setAmount(a.getAmount() - runes);
			} else if (a.getResource().equals("soldiers")) {
			   a.setAmount(a.getAmount() - soldiers);
			}

			if (a.getAmount() <= 0) {
			   toDelete.add(a);
			} else if (a.getAmount() != before) {
			   if (a.saveToDB()) {
				  out.add("Aid request updated");
			   }
			}
		 }
	  }
	  for (Aid a : toDelete) {
		 if (Aid.deleteFromDB(a.getProvname(), a.getResource())) {
			out.add("Aid request removed");
		 }
	  }
	  return out;
   }

   /**
    * Removes events that have already expired
    */
   public static void removeOldEvents() {
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM event WHERE eventtime <= ?");
		 ps.setTimestamp(1, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Resets the attendance list for the specified event
    * 
    * @param description
    * @return
    */
   public static boolean resetAttendance(final String description) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM attendance WHERE eventdescription = ?");
		 ps.setString(1, description);
		 if (ps.executeUpdate() >= 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Clears the claimed provinces list
    * 
    * @return
    */
   public static boolean resetClaimed() {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM claim");
		 ps.executeUpdate();
		 out = true;
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Resets the specified readiness type
    * 
    * @param type
    * @return
    */
   public static boolean resetReadiness(final String type) {
	  boolean out = false;
	  if (!"all".equalsIgnoreCase(type)) {
		 if (!Readiness.isReadinessType(type))
			return out;
		 if (!Readiness.readinessIsActive(type))
			return out;
	  }

	  PreparedStatement ps = null;
	  try {
		 if ("all".equalsIgnoreCase(type)) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("DELETE FROM readiness");
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM readiness WHERE readinesstype = ?");
			ps.setString(1, type);
		 }
		 ps.executeUpdate();

		 if (!"all".equalsIgnoreCase(type)) {
			out = true;
			setReadinessActivity(type, false);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets attendance information for the specified user and event
    * 
    * @param nick
    * @param attendance
    * @param description
    * @return
    */
   public static boolean setAttendance(final String nick, final String attendance, final String description) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM attendance WHERE mainnick = ? AND eventdescription = ?");
		 ps.setString(1, nick);
		 ps.setString(2, description);
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO attendance VALUES(?,?,?)");
		 ps.setString(1, nick);
		 ps.setString(2, description);
		 ps.setString(3, attendance);
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets a kd comment for the specified kd
    */
   public static boolean setKDComment(final String kd, final String comment) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kd WHERE loc = ?");
		 ps.setString(1, kd);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE kd SET comment = ? WHERE loc = ?");
			ps.setString(1, comment);
			ps.setString(2, kd);
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO kd VALUES(?,'','','',?,?,false,false)");
			ps.setString(1, kd.trim());
			ps.setString(2, comment);
			ps.setTimestamp(3, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets readiness for the specified user and type
    * 
    * @param nick
    * @param isDone
    * @param type
    * @return
    */
   public static List<String> setReadiness(final String nick, final boolean isDone, final String type) {
	  List<String> out = new LinkedList<String>();
	  if (!Readiness.isReadinessType(type) || !Readiness.readinessIsActive(type))
		 return out;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "readiness WHERE mainnick = ? AND readinesstype = ?");
		 ps.setString(1, nick);
		 ps.setString(2, type);
		 rs = ps.executeQuery();

		 if (!rs.next()) {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO readiness VALUES(?,?,?)");
			ps.setString(1, nick);
			ps.setBoolean(2, isDone);
			ps.setString(3, type);
			ps.executeUpdate();

			out.add(isDone ? "Set done!" : "Set ready!");
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE readiness SET " + "done = ? WHERE mainnick = ? AND readinesstype = ?");
			ps.setBoolean(1, isDone);
			ps.setString(2, nick);
			ps.setString(3, type);
			ps.executeUpdate();

			out.add(isDone ? "Set done!" : "Set ready!");
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Sets a readiness type as either active or inactive
    * 
    * @param type
    * @param active
    */
   public static void setReadinessActivity(final String type, final boolean active) {
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("UPDATE readinesslist SET " + "active = ? WHERE readinesstype = ?");
		 ps.setBoolean(1, active);
		 ps.setString(2, type);
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Sets the show status for a kd. Meant to be used for websites connected to the bot.
    * 
    * @param kd
    * @param show
    * @return
    */
   public static boolean setShowKD(final String kd, final boolean show) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kd WHERE loc = ?");
		 ps.setString(1, kd);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE kd SET showkd = ? WHERE loc = ?");
			ps.setBoolean(1, show);
			ps.setString(2, kd);
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO kd VALUES(?,'','','','',?,false,?)");
			ps.setString(1, kd.trim());
			ps.setTimestamp(2, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
			ps.setBoolean(3, show);
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Highlights users based on their attendance status for the specified event
    * 
    * @param attendance
    * @param description
    * @param channel
    */
   public static void slapEvent(final String attendance, final String description, final String channel) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "attendance WHERE attendance = ? AND eventdescription = ?");
		 ps.setString(1, attendance);
		 ps.setString(2, description);
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Updates the claimed provinces list when someone hit
    * 
    * @param prov
    */
   public static void updateClaimed(final String prov) {
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("UPDATE claim SET " + "timeshit = timeshit+1, claimedby = '' WHERE target = ?");
		 ps.setString(1, prov);
		 ps.executeUpdate();
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   public static boolean updateDragon(final String user, final int type, final int contribution) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM dragon WHERE player = ? AND dragontype = ?");
		 ps.setString(1, user);
		 ps.setInt(2, type);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			int contrib = rs.getInt("contribution") + contribution;

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("UPDATE dragon SET " + "contribution = ? WHERE player = ? AND dragontype = ?");
			ps.setInt(1, contrib);
			ps.setString(2, user);
			ps.setInt(3, type);
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 } else {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO dragon VALUES(?,?,?)");
			ps.setInt(1, type);
			ps.setString(2, user);
			ps.setInt(3, contribution);
			if (ps.executeUpdate() == 1) {
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private KDHandler() {
   }

   private boolean addOrderCategory(final String category) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO ordercategory VALUES(?)");
		 ps.setString(1, category);
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public boolean clearDragon(final int type) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM dragon WHERE dragontype = ?");
		 ps.setInt(1, type);
		 ps.executeUpdate();
		 out = true;
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private boolean delOrderCategory(final String category) {
	  boolean out = false;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM ordercategory WHERE category = ?");
		 ps.setString(1, category);
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns a string that corresponds to the command needed to add the specified build Meant to make it easier to add small
    * changes without having to retype the whole command
    * 
    * @param racepers
    * @param type
    * @return
    */
   private List<String> getBuildString(final String racepers, final String type) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM build WHERE racepers = ? AND buildtype = ?");
		 ps.setString(1, racepers);
		 ps.setString(2, type);
		 rs = ps.executeQuery();

		 if (rs.next()) {
			String buildString = "addbuild " + rs.getString("racepers") + " ospa " + rs.getDouble("ospa") + " dspa "
				  + rs.getDouble("dspa") + " epa " + rs.getDouble("epa") + " tpa " + rs.getDouble("tpa") + " wpa "
				  + rs.getDouble("wpa") + " type " + rs.getString("buildtype") + " ";
			for (String s : rs.getString("buildings").split("\n")) {
			   buildString += s.replace('\t', ' ') + " ";
			}
			out.add(buildString.trim());
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public List<String> getDragonStats(final int type) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM dragon WHERE dragontype = ?" + " ORDER BY contribution DESC");
		 ps.setInt(1, type);
		 rs = ps.executeQuery();

		 StringBuilder output = new StringBuilder(370);
		 int counter = 1;
		 NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
		 nf.setGroupingUsed(true);
		 while (rs.next()) {
			if (output.length() > 350) {
			   out.add(output.toString());
			   output = new StringBuilder(370);
			}
			output.append(Colors.NORMAL + counter + "." + Colors.BLUE + rs.getString("player") + Colors.NORMAL + "("
				  + Colors.OLIVE + nf.format(rs.getInt("contribution")) + Colors.NORMAL + ") | ");
			++counter;
		 }
		 if (output.length() > 0) {
			out.add(output.toString());
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the id of an event based on its position in the event list
    * 
    * @param listposition
    * @return
    */
   private String getEventID(final int listposition) {
	  String out = "";
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "event WHERE eventtype = false ORDER BY eventtime DESC");
		 rs = ps.executeQuery();

		 int counter = 0;
		 while (rs.next()) {
			++counter;
			if (counter == listposition) {
			   out = rs.getString("description");
			   break;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private String getOrderCategoryRegex() {
	  String out = "";
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM ordercategory");
		 rs = ps.executeQuery();

		 StringBuilder output = new StringBuilder(100);
		 while (rs.next()) {
			output.append(rs.getString("category") + "|");
		 }
		 if (output.length() > 0) {
			out = "\\[(" + output.toString().substring(0, output.length() - 1) + ")\\]";
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public List<String> getPlayerDragonStats(final String user, final int... type) {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 if (type.length != 0) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM dragon WHERE player = ? AND dragontype = ?");
			ps.setString(1, user);
			ps.setInt(2, type[0]);
			rs = ps.executeQuery();
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM dragon WHERE player = ?");
			ps.setString(1, user);
			rs = ps.executeQuery();
		 }

		 while (rs.next()) {
			out.add(rs.getString("player") + "'s dragon stats (" + (rs.getInt("dragontype") == 1 ? "kill): " : "send): ")
				  + rs.getInt("contribution"));
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns the nicks of the registered players, grouping them based on what country they are from
    * 
    * @return
    */
   private List<String> getRoster() {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT mainnick,country FROM kdmember");
		 rs = ps.executeQuery();

		 final HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
		 while (rs.next()) {
			String country = rs.getString("country");
			if ("".equals(country)) {
			   country = "Unknown";
			}
			String nick = rs.getString("mainnick");

			if (country.equalsIgnoreCase("usa")) {
			   country = "USA";
			} else if (country.equalsIgnoreCase("uk")) {
			   country = "UK";
			} else {
			   country = StringTools.capitalizeFirstLetters(country);
			}

			if (map.containsKey(country)) {
			   map.get(country).add(nick);
			} else {
			   final ArrayList<String> temp = new ArrayList<String>();
			   temp.add(nick);
			   map.put(country, temp);
			}
		 }

		 for (final Entry<String, ArrayList<String>> e : map.entrySet()) {
			String names = "";
			for (String s : e.getValue()) {
			   names += s + " ";
			}
			out.add(Colors.OLIVE + e.getKey() + "(" + e.getValue().size() + "): " + Colors.BLUE + names.trim());
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   @Override
   public void handle(final IRCCommand command, final IRCOutput output) {
   }

   public void handleAddbuild(final IRCCommand command, final IRCOutput out) {
	  if (command.size() >= 4) {
		 String msg = command.getFullMessage().toLowerCase();
		 msg = msg.replace("%", "");
		 String raceregex = CommonMethods.getRacesRegex(false).toLowerCase();
		 String persregex = CommonMethods.getPersonalitiesRegex().toLowerCase();
		 String race = StringTools.extractPartialString(raceregex, msg);
		 String pers = StringTools.extractPartialString(persregex, msg);
		 String racepers = (StringTools.capitalizeFirstLetters(race) + " " + StringTools.capitalizeFirstLetters(pers)).trim();
		 if (!racepers.toLowerCase().matches(raceregex + " " + persregex) && !racepers.toLowerCase().matches(raceregex))
			return;
		 msg = msg.replaceFirst(racepers.toLowerCase(), "").trim();

		 String[] split = msg.split(" ");
		 if (split.length % 2 != 0)
			return;

		 Map<String, String> buildings = new HashMap<String, String>();
		 double ospa = 0;
		 double dspa = 0;
		 double epa = 0;
		 double tpa = 0;
		 double wpa = 0;
		 String type = "default";
		 for (int i = 0; i < split.length; i = i + 2) {
			try {
			   Double num = 0.0;
			   if (!"type".equals(split[i])) {
				  num = Double.parseDouble(split[i + 1]);
			   }

			   if (split[i].equals("ospa")) {
				  ospa = num;
			   } else if (split[i].equals("dspa")) {
				  dspa = num;
			   } else if (split[i].equals("epa")) {
				  epa = num;
			   } else if (split[i].equals("tpa")) {
				  tpa = num;
			   } else if (split[i].equals("wpa")) {
				  wpa = num;
			   } else if (split[i].equals("type")) {
				  type = split[i + 1];
			   } else if (split[i].matches(CommonMethods.getBuildingsRegex())) {
				  buildings.put(split[i], String.valueOf(num));
			   }
			} catch (final NumberFormatException e) {
			   Logger.getLogger("Error").error("", e);
			   return;
			}
		 }
		 if (new Build(racepers, type, ospa, dspa, epa, tpa, wpa, buildings, GregorianCalendar.getInstance().getTimeInMillis())
			   .saveToDB()) {
			out.addOutput("Build added");
			Bot.getInstance().sendMessage(Main.getBotSettings().getMainChannel(), Colors.RED + "Build added for " + racepers);
		 }
	  }
   }

   public void handleAddevent(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 4) {
		 String wavedate = command.getPartialMessage(1, 4);
		 Date date;
		 if (command.validate(1, 4, InputType.UTODATE)) {
			UtopiaTime ut;
			try {
			   ut = new UtopiaTime(wavedate);
			   date = new Date(ut.getTime());
			   if (date.getTime() <= GregorianCalendar.getInstance().getTimeInMillis())
				  return;
			} catch (final UtoDateException e) {
			   Logger.getLogger("Error").error("", e);
			   return;
			}

		 } else {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM d HH:mm", Locale.US);
			sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
			try {
			   Calendar cal = Calendar.getInstance();
			   date = sdf.parse(cal.get(Calendar.YEAR) + " " + wavedate);
			   if (date.getTime() <= GregorianCalendar.getInstance().getTimeInMillis()) {
				  cal.add(Calendar.YEAR, 1);
				  date = sdf.parse(cal.get(Calendar.YEAR) + " " + wavedate);
			   }
			} catch (final Exception e) {
			   out.addOutput("Incorrect date. Utodate: January 1st, YR8 Regular Date: October 28 18:00 "
					 + "(note that the time should be in GMT)");
			   return;
			}
		 }

		 String description = command.getPartialMessage(4, command.size());
		 if (new Event(description, date.getTime(), false, GregorianCalendar.getInstance().getTimeInMillis()).saveToDB()) {
			out.addOutput("Event added");
			Bot.getInstance().sendMessage(Main.getBotSettings().getMainChannel(),
				  Colors.RED + "An event has been scheduled. Check !events");
		 }
	  }
   }

   public void handleAddnap(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 if (command.validate(1, InputType.KDLOC)) {
			if (command.size() == 2) {
			   if (new Nap(command.get(1), 0L, GregorianCalendar.getInstance().getTimeInMillis()).saveToDB()) {
				  out.addOutput("Nap added");
			   }
			} else {
			   String date = command.getPartialMessage(2, command.size());
			   if (command.validate(2, command.size(), InputType.UTODATE)) {
				  try {
					 if (new Nap(command.get(1), new UtopiaTime(date).getTime(), GregorianCalendar.getInstance()
						   .getTimeInMillis()).saveToDB()) {
						out.addOutput("Nap added");
					 } else {
						out.addOutput("Wrong end date format, use for example May 23rd, YR8");
					 }
				  } catch (UtoDateException e) {
				  }
			   }
			}
		 } else {
			out.addOutput("Wrong kd loc format. Use (xx:xx)");
		 }
	  }
   }

   public void handleAddorder(final IRCCommand command, final IRCOutput out) {
	  String msg = "";
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 msg = command.getFullMessage();
		 String categoriesRegex = getOrderCategoryRegex();
		 String category = "";
		 if (!"".equals(categoriesRegex) && msg.matches(".*" + categoriesRegex + " .*")) {
			category = StringTools.extractPartialString(categoriesRegex, msg);
			category = category.substring(1, category.length() - 1);
			msg = msg.replaceFirst(categoriesRegex, "").trim();
		 }
		 String orderTo = "";
		 String raceregex = CommonMethods.getRacesRegex(false);
		 String persregex = CommonMethods.getPersonalitiesRegex();
		 Matcher matcher = Pattern.compile(raceregex + " " + persregex + " (.*)").matcher(msg);
		 if (matcher.matches()) {
			String race = matcher.group(1);
			String pers = matcher.group(2);
			msg = matcher.group(3);

			race = StringTools.capitalizeFirstLetters(race);
			pers = StringTools.capitalizeFirstLetters(pers);
			orderTo = race + " " + pers;
		 } else if (command.size() > 2 && "".equals(CommonMethods.getUserFromDB(msg.substring(0, msg.indexOf(' ')), true))) {
			if (msg.matches(raceregex + " .*")) {
			   matcher = Pattern.compile(raceregex + " (.*)").matcher(msg);
			   matcher.matches();
			   String race = matcher.group(1);
			   msg = matcher.group(2);

			   race = StringTools.capitalizeFirstLetters(race);
			   orderTo = race;
			} else if (msg.toLowerCase().matches(persregex + " .*")) {
			   matcher = Pattern.compile(persregex + " (.*)").matcher(msg);
			   matcher.matches();
			   String pers = matcher.group(1);
			   msg = matcher.group(2);

			   pers = StringTools.capitalizeFirstLetters(pers);
			   orderTo = pers;
			}
		 } else if (command.size() > 2) {
			orderTo = CommonMethods.getUserFromDB(msg.substring(0, msg.indexOf(' ')), true);

			msg = msg.substring(msg.indexOf(' ') + 1);
		 }
		 final String message = msg;
		 if (new Order(0, msg, orderTo, category, GregorianCalendar.getInstance().getTimeInMillis()).saveToDB()) {
			addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "orders");
			out.addOutput("Order added");
			Bot.getInstance().sendMessage(Main.getBotSettings().getMainChannel(),
				  Colors.RED + "New order added. Check " + Main.getBotSettings().getCommandPrefix() + "orders new");
			new Thread() {

			   @Override
			   public void run() {
				  CommonMethods.doSMSNotification("", 3, message);
			   }
			}.start();
		 }
	  }
   }

   public void handleAddordercategory(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() == 2
			&& addOrderCategory(command.get(1))) {
		 out.addOutput("Order category added");
	  }
   }

   public void handleAid(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 String user = UserCentral.getInstance().getOnlineUser(command.getSender());
		 String race = CommonMethods.getRace(user);
		 String pers = CommonMethods.getPersonality(user);
		 String racepers = race + " " + pers;
		 String orders = getNewOrdersAmount(command.getSender()) > 0 ? Colors.RED + "orders ("
			   + getNewOrdersAmount(command.getSender()) + " new)" : Colors.DARK_GREEN + "orders";
		 String events = getNewEventsAmount(user) > 0 ? Colors.RED + "events (" + getNewEventsAmount(user) + " new)"
			   : Colors.DARK_GREEN + "events";
		 String naps = getNewNapsAmount(user) > 0 ? Colors.RED + "naps (" + getNewNapsAmount(user) + " new)" : Colors.DARK_GREEN
			   + "naps";
		 String build = getNewBuildCheck(user, racepers) ? Colors.RED + "build (new)" : Colors.DARK_GREEN + "build";
		 String wave = getNewWaveCheck(user) ? Colors.RED + "wave (new)" : Colors.DARK_GREEN + "wave";
		 out.addOutput(orders + Colors.NORMAL + " | " + Colors.BOLD + "aid" + Colors.NORMAL + " | " + wave + Colors.NORMAL
			   + " | " + events + Colors.NORMAL + " | " + build + Colors.NORMAL + " | " + naps);
		 int counter = 1;
		 String tz = CommonMethods.getUserTimeZone(UserCentral.getInstance().getOnlineUser(command.getSender()));
		 for (Aid aid : Aid.getAidList()) {
			out.addOutput(aid.getIRCOutput(0, tz, String.valueOf(counter)));
			++counter;
		 }
		 addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "aid");
	  } else if (command.size() >= 3) {
		 if (command.validate(1, InputType.AMOUNT) && command.get(2).toLowerCase().matches("(food|gc|runes|soldiers)")) {
			String prov = CommonMethods.getProv(UserCentral.getInstance().getOnlineUser(command.getSender()));
			if ("".equals(prov)) {
			   out.addOutput("You're not registered to a province");
			} else {
			   String temp = command.get(1);
			   temp = temp.replaceAll(",", "");
			   Double d = Double.parseDouble(temp.replaceAll("k", ""));
			   int ks = temp.replaceAll("[^k]", "").length();
			   d = d * Math.pow(1000, ks);

			   String urgency = Colors.DARK_GREEN + "NORMAL";
			   if (command.size() == 4) {
				  if (command.get(3).equalsIgnoreCase("urgent")) {
					 urgency = Colors.RED + "URGENT";
				  } else if (command.get(3).equalsIgnoreCase("low")) {
					 urgency = Colors.TEAL + "LOW PRIORITY";
				  }
			   }

			   if (new Aid(prov, command.get(2).toLowerCase(), d.intValue(), GregorianCalendar.getInstance().getTimeInMillis(),
					 urgency).saveToDB()) {
				  out.addOutput("Aid request added");
			   }
			}

		 } else if (command.size() >= 4 && command.validate(2, InputType.AMOUNT)
			   && command.get(3).toLowerCase().matches("(food|gc|runes|soldiers)")) {
			String prov = CommonMethods.getProv(CommonMethods.getUserFromDB(command.get(1), false));
			if ("".equals(prov)) {
			   out.addOutput("That user is not registered to a province");
			} else {
			   String temp = command.get(2);
			   temp = temp.replaceAll(",", "");
			   Double d = Double.parseDouble(temp.replaceAll("k", ""));
			   int ks = temp.replaceAll("[^k]", "").length();
			   d = d * Math.pow(1000, ks);

			   String urgency = Colors.DARK_GREEN + "NORMAL";
			   if (command.size() == 5) {
				  if (command.get(4).equalsIgnoreCase("urgent")) {
					 urgency = Colors.RED + "URGENT";
				  } else if (command.get(4).equalsIgnoreCase("low")) {
					 urgency = Colors.TEAL + "LOW PRIORITY";
				  }
			   }

			   if (new Aid(prov, command.get(3).toLowerCase(), d.intValue(), GregorianCalendar.getInstance().getTimeInMillis(),
					 urgency).saveToDB()) {
				  out.addOutput("Aid request added");
			   }
			}
		 } else {
			out.addOutput("Incorrect input");
		 }
	  }
   }

   public void handleAttendance(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 Attendance attendance = Attendance.getAttendance("");
		 if (attendance != null) {
			out.addOutput(attendance.getIRCOutput(0));
		 }
	  } else if (command.size() == 2 && UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())
			&& command.get(1).equals("reset")) {
		 if (resetAttendance("")) {
			out.addOutput("Attendance reset");
		 }
	  } else if (command.size() == 2 && command.isInt(1)) {
		 Attendance attendance = Attendance.getAttendance(getEventID(Integer.parseInt(command.get(1))));
		 if (attendance != null) {
			out.addOutput(attendance.getIRCOutput(0));
		 }
	  } else if (command.size() == 3 && UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())
			&& command.get(1).equals("reset") && command.isInt(2))
		 if (resetAttendance(getEventID(Integer.parseInt(command.get(2))))) {
			out.addOutput("Attendance reset");
		 }
   }

   public void handleBuild(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(toBuild(UserCentral.getInstance().getOnlineUser(command.getSender()), "default"));
	  } else if (command.size() >= 2) {
		 if (command.getFullMessage().matches(
			   "(?i)" + CommonMethods.getRacesRegex(false) + " " + CommonMethods.getPersonalitiesRegex())
			   || command.getFullMessage().matches("(?i)" + CommonMethods.getRacesRegex(false))) {
			List<Build> buildList = Build.getBuilds(command.getFullMessage());
			if (buildList.size() == 1) {
			   Build build = buildList.get(0);
			   if (build != null) {
				  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
				  String race = CommonMethods.getRace(user);
				  String pers = CommonMethods.getPersonality(user);
				  if (build.getRacepers().equalsIgnoreCase(race) || build.getRacepers().equalsIgnoreCase(race + " " + pers)) {
					 addUserCheck(user, "build");
				  }
				  out.addOutput(build.getIRCOutput(0));
			   }
			} else {
			   String output = "";
			   String temp = "";
			   for (Build build : buildList) {
				  if (!command.getFullMessage().matches("(?i).*" + CommonMethods.getPersonalitiesRegex())) {
					 temp = " (" + build.getRacepers().replaceFirst(CommonMethods.getRacesRegex(false), "").trim() + ")";
				  } else {
					 temp = "";
				  }
				  output += build.getType() + temp + ", ";
			   }
			   if (output.length() > 0) {
				  out.addOutput("Builds for " + command.getFullMessage() + ": " + output.substring(0, output.length() - 2));
			   }
			}
		 } else if (command.size() == 2 && "all".equals(command.get(1))) {
			List<Build> buildList = Build.getBuilds("%");
			Map<String, String> builds = new HashMap<String, String>();
			for (final Build build : buildList) {
			   if (builds.containsKey(build.getRacepers())) {
				  builds.put(build.getRacepers(), builds.get(build.getRacepers()) + build.getType() + ", ");
			   } else {
				  builds.put(build.getRacepers(), build.getType() + ", ");
			   }
			}
			for (Entry<String, String> e : builds.entrySet()) {
			   out.addOutput("Builds for " + e.getKey() + ": " + e.getValue());
			}
		 } else if (command.size() == 2 && !"".equals(CommonMethods.getUserFromDB(command.get(1), false))) {
			out.addOutput(toBuild(CommonMethods.getUserFromDB(command.get(1), false), "default"));
		 } else if (command.size() == 3 && !"".equals(CommonMethods.getUserFromDB(command.get(1), false))) {
			out.addOutput(toBuild(CommonMethods.getUserFromDB(command.get(1), false), command.get(2)));
		 } else {
			Build build = Build.getBuild(
				  StringTools.extractPartialString(CommonMethods.getRacesRegex(false), command.getFullMessage()),
				  StringTools.extractPartialString(CommonMethods.getPersonalitiesRegex(), command.getFullMessage()),
				  command.get(command.size() - 1));
			if (build != null) {
			   String user = UserCentral.getInstance().getOnlineUser(command.getSender());
			   String race = CommonMethods.getRace(user);
			   String pers = CommonMethods.getPersonality(user);
			   if (build.getRacepers().equalsIgnoreCase(race) || build.getRacepers().equalsIgnoreCase(race + " " + pers)) {
				  addUserCheck(user, "build");
			   }
			   out.addOutput(build.getIRCOutput(0));
			}
		 }
	  }
   }

   public void handleClaim(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(listClaimed());
	  } else {
		 String target = command.getFullMessage();
		 target = target.replaceAll("\\([0-9]{1,2}(:)[0-9]{1,2}\\)", "");
		 if ("".equals(CommonMethods.provinceExists(target)))
			return;
		 ClaimedTarget existingTarget = null;
		 ClaimedTarget previousClaim = null;
		 for (ClaimedTarget ct : ClaimedTarget.getClaimed()) {
			if (ct.getTarget().equals(target)) {
			   existingTarget = ct;
			}
			if (ct.getClaimedBy().equals(UserCentral.getInstance().getOnlineUser(command.getSender()))) {
			   previousClaim = ct;
			}
		 }
		 if (existingTarget == null || existingTarget != null && "".equals(existingTarget.getClaimedBy())) {
			if (previousClaim != null) {
			   ClaimedTarget.deleteFromDB(previousClaim.getClaimedBy());
			}
			if (new ClaimedTarget(target, UserCentral.getInstance().getOnlineUser(command.getSender()),
				  existingTarget == null ? 0 : existingTarget.getTimesHit()).saveToDB()) {
			   Bot.getInstance().sendMessage(
					 Main.getBotSettings().getMainChannel(),
					 Colors.BLUE + UserCentral.getInstance().getOnlineUser(command.getSender()) + Colors.OLIVE + " claims "
						   + Colors.RED + target);
			}
		 } else {
			out.addOutput("That target has already been claimed");
		 }
	  }
   }

   public void handleDone(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(setReadiness(UserCentral.getInstance().getOnlineUser(command.getSender()), true, "attack"));
	  } else {
		 if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
			if (command.size() == 2) {
			   String user = CommonMethods.getUserFromDB(command.get(1), false);
			   if ("".equals(user))
				  return;
			   out.addOutput(setReadiness(user, true, "attack"));
			} else {
			   String user = CommonMethods.getUserFromDB(command.get(1), false);
			   if ("".equals(user))
				  return;
			   out.addOutput(setReadiness(user, true, command.get(2).toLowerCase()));
			}
		 }
	  }
   }

   public void handleDragon(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(getPlayerDragonStats(UserCentral.getInstance().getOnlineUser(command.getSender())));
	  } else if (command.size() == 2) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if (!"".equals(user)) {
			out.addOutput(getPlayerDragonStats(user));
		 } else if ("kill".equalsIgnoreCase(command.get(1))) {
			out.addOutput(getDragonStats(1));
		 } else if ("send".equalsIgnoreCase(command.get(1))) {
			out.addOutput(getDragonStats(2));
		 } else if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())
			   && "reset".equalsIgnoreCase(command.get(1)) && clearDragon(1) && clearDragon(2)) {
			out.addOutput(Colors.RED + "Dragon tracking lists cleared");
		 }
	  } else if (command.size() == 3) {
		 String user = CommonMethods.getUserFromDB(command.get(1), false);
		 if (!"".equals(user) && ("kill".equalsIgnoreCase(command.get(2)) || "send".equalsIgnoreCase(command.get(2)))) {
			out.addOutput(getPlayerDragonStats(user, "kill".equalsIgnoreCase(command.get(2)) ? 1 : 2));
		 } else if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())
			   && "reset".equalsIgnoreCase(command.get(1))
			   && ("kill".equalsIgnoreCase(command.get(2)) || "send".equalsIgnoreCase(command.get(2)))
			   && clearDragon("kill".equalsIgnoreCase(command.get(2)) ? 1 : 2)) {
			out.addOutput(Colors.RED + "Dragon tracking " + command.get(2) + " list cleared");
		 }
	  }
   }

   public void handleEvents(final IRCCommand command, final IRCOutput out) {
	  addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "events");
	  if (command.size() == 1) {
		 int counter = 1;
		 String user = UserCentral.getInstance().getOnlineUser(command.getSender());
		 String race = CommonMethods.getRace(user);
		 String pers = CommonMethods.getPersonality(user);
		 String racepers = race + " " + pers;
		 String orders = getNewOrdersAmount(command.getSender()) > 0 ? Colors.RED + "orders ("
			   + getNewOrdersAmount(command.getSender()) + " new)" : Colors.DARK_GREEN + "orders";
		 String aid = getNewAidAmount(user) > 0 ? Colors.RED + "aid (" + getNewAidAmount(user) + " new)" : Colors.DARK_GREEN
			   + "aid";
		 String naps = getNewNapsAmount(user) > 0 ? Colors.RED + "naps (" + getNewNapsAmount(user) + " new)" : Colors.DARK_GREEN
			   + "naps";
		 String build = getNewBuildCheck(user, racepers) ? Colors.RED + "build (new)" : Colors.DARK_GREEN + "build";
		 String wave = getNewWaveCheck(user) ? Colors.RED + "wave (new)" : Colors.DARK_GREEN + "wave";
		 out.addOutput(orders + Colors.NORMAL + " | " + aid + Colors.NORMAL + " | " + wave + Colors.NORMAL + " | " + Colors.BOLD
			   + "events" + Colors.NORMAL + " | " + build + Colors.NORMAL + " | " + naps);
		 for (Event event : Event.getEvents()) {
			out.addOutput(event.getIRCOutput(Constants.EVENT,
				  CommonMethods.getUserTimeZone(UserCentral.getInstance().getOnlineUser(command.getSender())), "" + counter));
			++counter;
		 }
	  } else if (command.size() == 3 && command.isInt(1) && command.get(2).equalsIgnoreCase("attending"))
		 if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), "attending",
			   getEventID(Integer.parseInt(command.get(1))))) {
			out.addOutput("Attendance info set");
		 } else if (command.size() == 4 && command.isInt(1) && command.get(2).equalsIgnoreCase("not")
			   && command.get(3).equalsIgnoreCase("attending"))
			if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), "not attending",
				  getEventID(Integer.parseInt(command.get(1))))) {
			   out.addOutput("Attendance info set");
			} else if (command.size() == 4 && command.isInt(1) && command.get(2).equalsIgnoreCase("late")
				  && command.get(3).matches("[0-9]{1,5}(m|h)"))
			   if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), command.get(3),
					 getEventID(Integer.parseInt(command.get(1))))) {
				  out.addOutput("Attendance info set");
			   }
   }

   public void handleGetbuild(final IRCCommand command, final IRCOutput out) {
	  if (command.size() >= 2) {
		 out.addOutput(getBuildString(command.getPartialMessage(1, command.size() - 1), command.get(command.size() - 1)));
	  }
   }

   public void handleKd(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput(KDtoDB.getKD("(" + Main.getBotSettings().getKdLoc() + ")").getIRCOutput(false));
	  } else {
		 if (command.validate(1, InputType.KDLOC)) {
			KD kd = KDtoDB.getKD(command.get(1));
			if (kd != null) {
			   out.addOutput(KDtoDB.getKD(command.get(1)).getIRCOutput(false));
			}
		 }
	  }
   }

   public void handleNaps(final IRCCommand command, final IRCOutput out) {
	  addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "naps");
	  String user = UserCentral.getInstance().getOnlineUser(command.getSender());
	  String race = CommonMethods.getRace(user);
	  String pers = CommonMethods.getPersonality(user);
	  String racepers = race + " " + pers;
	  String orders = getNewOrdersAmount(command.getSender()) > 0 ? Colors.RED + "orders ("
			+ getNewOrdersAmount(command.getSender()) + " new)" : Colors.DARK_GREEN + "orders";
	  String aid = getNewAidAmount(user) > 0 ? Colors.RED + "aid (" + getNewAidAmount(user) + " new)" : Colors.DARK_GREEN + "aid";
	  String events = getNewEventsAmount(user) > 0 ? Colors.RED + "events (" + getNewEventsAmount(user) + " new)"
			: Colors.DARK_GREEN + "events";
	  String build = getNewBuildCheck(user, racepers) ? Colors.RED + "build (new)" : Colors.DARK_GREEN + "build";
	  String wave = getNewWaveCheck(user) ? Colors.RED + "wave (new)" : Colors.DARK_GREEN + "wave";
	  out.addOutput(orders + Colors.NORMAL + " | " + aid + Colors.NORMAL + " | " + wave + Colors.NORMAL + " | " + events
			+ Colors.NORMAL + " | " + build + Colors.NORMAL + " | " + Colors.BOLD + "naps");
	  if (command.size() == 1) {
		 out.addOutput(listNaps("", false));
	  } else if (command.get(1).equals("full")) {
		 out.addOutput(listNaps("", true));
	  } else {
		 out.addOutput(listNaps(command.get(1), true));
	  }
   }

   public void handleOrdercategories(final IRCCommand command, final IRCOutput out) {
	  out.addOutput(listOrderCategories());
   }

   public void handleOrders(final IRCCommand command, final IRCOutput out) {
	  setReadiness(UserCentral.getInstance().getOnlineUser(command.getSender()), true, "order");
	  if (command.size() == 2 && command.get(1).equals("new")) {
		 out.addOutput(listOrders(command.getSender(), true, true));
	  } else {
		 out.addOutput(listOrders(command.getSender(), false, true));
	  }
   }

   public void handleReadiness(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 Readiness r = Readiness.getReadiness("attack");
		 if (r != null) {
			out.addOutput(r.getIRCOutput(0));
		 }
	  } else if (command.size() == 2) {
		 if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
			if (command.get(1).equalsIgnoreCase("reset") || command.get(1).equalsIgnoreCase("stop")) {
			   if (resetReadiness("attack")) {
				  out.addOutput("Readiness reset");
			   }
			} else if (command.get(1).equalsIgnoreCase("start")) {
			   if (startReadiness("attack", false)) {
				  out.addOutput("Readiness for attack started");
				  out.addOutput(Colors.RED + "Readiness for attack started");
			   }
			} else {
			   Readiness r = Readiness.getReadiness(command.get(1));
			   if (r != null) {
				  out.addOutput(r.getIRCOutput(0));
			   }
			}
		 }
	  } else {
		 if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel())) {
			if (command.get(1).equalsIgnoreCase("start")) {
			   if (command.get(2).equalsIgnoreCase("attack")) {
				  if (startReadiness("attack", true)) {
					 out.addOutput("Readiness for attack started");
					 out.addOutput(Colors.RED + "Readiness for attack started");
				  }
			   } else if (command.get(2).equalsIgnoreCase("aid")) {
				  if (startReadiness("aid", true)) {
					 out.addOutput("Readiness for aid started");
					 out.addOutput(Colors.RED + "Readiness for aid started");
				  }
			   } else if (command.get(2).equalsIgnoreCase("order"))
				  if (startReadiness("order", true)) {
					 out.addOutput("Readiness for order started");
					 out.addOutput(Colors.RED + "Readiness for order started");
				  }
			} else if (command.get(1).equalsIgnoreCase("reset") || command.get(1).equalsIgnoreCase("stop"))
			   if (resetReadiness(command.get(2))) {
				  out.addOutput("Readiness reset");
			   }
		 }
	  }
   }

   public void handleReady(final IRCCommand command, final IRCOutput out) {
	  out.addOutput(setReadiness(UserCentral.getInstance().getOnlineUser(command.getSender()), false, "attack"));
   }

   public void handleRemoveaid(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 out.addOutput("Input # to delete");
	  } else {
		 if (command.isInt(1)) {
			out.addOutput(delAid(Integer.parseInt(command.get(1))));
		 }
	  }
   }

   public void handleRemovebuild(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 2) {
		 if (Build.deleteFromDB(command.getPartialMessage(1, command.size() - 1), command.get(command.size() - 1))) {
			out.addOutput("Build deleted");
		 }
	  }
   }

   public void handleRemoveevent(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 if (command.isInt(1)) {
			if (Event.deleteFromDB(String.valueOf(getEventID(Integer.parseInt(command.get(1)))))) {
			   out.addOutput("Event deleted");
			}
		 } else {
			out.addOutput("Incorrect input");
		 }
	  }
   }

   public void handleRemovenap(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1) {
		 if (command.validate(1, InputType.KDLOC))
			if (Nap.deleteFromDB(command.get(1))) {
			   out.addOutput("Nap deleted");
			} else {
			   out.addOutput("Incorrect input. Use kd format (xx:xx)");
			}
	  }
   }

   public void handleRemoveorder(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() > 1
			&& command.isInt(1))
		 if (Order.deleteFromDB(String.valueOf(getOrderID(Integer.parseInt(command.get(1)))))) {
			out.addOutput("Order deleted");
		 }
   }

   public void handleRemoveordercategory(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() == 2
			&& delOrderCategory(command.get(1))) {
		 out.addOutput("Order category removed");
	  }
   }

   public void handleRemovewave(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()))
		 if (Event.deleteFromDB("")) {
			out.addOutput("Wave deleted");
		 }
   }

   public void handleResetclaim(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()))
		 if (resetClaimed()) {
			out.addOutput("Claimed list reset");
			Bot.getInstance().sendMessage(Main.getBotSettings().getMainChannel(), Colors.RED + "Claimed list reset");
		 }
   }

   public void handleRoster(final IRCCommand command, final IRCOutput out) {
	  out.addOutput(getRoster());
   }

   public void handleSetkdcomment(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() >= 3) {
		 if (command.validate(1, InputType.KDLOC))
			if (setKDComment(command.get(1), command.getPartialMessage(2, command.size()))) {
			   out.addOutput("Kd comment set");
			}
	  }
   }

   public void handleSetwave(final IRCCommand command, final IRCOutput out) {
	  if (UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()) && command.size() == 4) {
		 String wavedate = command.getPartialMessage(1, 4);
		 Date date;
		 if (command.validate(1, 4, InputType.UTODATE)) {
			UtopiaTime ut;
			try {
			   ut = new UtopiaTime(wavedate);
			   date = new Date(ut.getTime());
			   if (date.getTime() < GregorianCalendar.getInstance().getTimeInMillis())
				  return;
			} catch (final UtoDateException e) {
			   Logger.getLogger("Error").error("", e);
			   return;
			}
		 } else {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM d HH:mm", Locale.US);
			sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
			try {
			   Calendar cal = Calendar.getInstance();
			   date = sdf.parse(cal.get(Calendar.YEAR) + " " + wavedate);
			   if (date.getTime() <= GregorianCalendar.getInstance().getTimeInMillis()) {
				  cal.add(Calendar.YEAR, 1);
				  date = sdf.parse(cal.get(Calendar.YEAR) + " " + wavedate);
			   }
			} catch (final Exception e) {
			   out.addOutput("Incorrect date. Utodate: January 1st, YR8 Regular Date: "
					 + "October 28 18:00 (note that the time should be in GMT)");
			   return;
			}
		 }
		 if (new Event("", date.getTime(), true, GregorianCalendar.getInstance().getTimeInMillis()).saveToDB()) {
			out.addOutput("Wave added");
			Bot.getInstance().sendMessage(Main.getBotSettings().getMainChannel(),
				  Colors.RED + "A wave has been scheduled. Check !wave");
		 }
	  }
   }

   public void handleSlap(final IRCCommand command, final IRCOutput out) {
	  if (!UserCentral.getInstance().onlineUserIsAdmin(command.getSender(), command.getChannel()))
		 return;
	  if (command.size() == 1) {
		 slapKD(command.getChannel());
	  } else if (command.size() == 2) {
		 if (command.get(1).equalsIgnoreCase("all")) {
			slapAll(command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("wave")) {
			slapEvent("attending", "", command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("readiness")) {
			slapReadiness(false, command.getChannel(), "attack");
		 } else {
			if (command.get(1).toLowerCase().matches(CommonMethods.getRacesRegex(false).toLowerCase())
				  || command.get(1).toLowerCase().matches(CommonMethods.getPersonalitiesRegex().toLowerCase())) {
			   slapRacePers(command.getChannel(), command.get(1));
			}
		 }
	  } else if (command.size() == 3) {
		 if (command.get(1).equalsIgnoreCase("wave") && command.get(2).equalsIgnoreCase("attending")) {
			slapEvent("attending", "", command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("armies") && command.get(2).equalsIgnoreCase("home")) {
			slapArmiesHome(command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("wave") && command.get(2).equalsIgnoreCase("unregistered")) {
			slapEventUnregistered("", command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("event") && command.isInt(2)) {
			slapEvent("attending", getEventID(Integer.parseInt(command.get(2))), command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("readiness") && command.get(2).equalsIgnoreCase("waiting")) {
			slapReadiness(false, command.getChannel(), "attack");
		 } else if (command.get(1).equalsIgnoreCase("readiness") && command.get(2).equalsIgnoreCase("done")) {
			slapReadiness(true, command.getChannel(), "attack");
		 } else if (command.get(1).equalsIgnoreCase("readiness") && command.get(2).equalsIgnoreCase("unregistered")) {
			slapReadinessUnregistered(command.getChannel(), "attack");
		 } else {
			String racepers = command.get(1) + " " + command.get(2);
			if (racepers.toLowerCase().matches(CommonMethods.getRacesRegex(false).toLowerCase())
				  || racepers.toLowerCase().matches(CommonMethods.getPersonalitiesRegex().toLowerCase())) {
			   slapRacePers(command.getChannel(), racepers);
			}
		 }
	  } else if (command.size() == 4) {
		 if (command.get(1).equalsIgnoreCase("wave") && command.get(2).equalsIgnoreCase("not")
			   && command.get(3).equalsIgnoreCase("attending")) {
			slapEvent("not attending", "", command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("event") && command.isInt(2) && command.get(3).equalsIgnoreCase("attending")) {
			slapEvent("attending", getEventID(Integer.parseInt(command.get(2))), command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("event") && command.isInt(2)
			   && command.get(3).equalsIgnoreCase("unregistered")) {
			slapEventUnregistered(getEventID(Integer.parseInt(command.get(2))), command.getChannel());
		 } else if (command.get(1).equalsIgnoreCase("readiness") && Readiness.isReadinessType(command.get(2).toLowerCase())
			   && command.get(3).equalsIgnoreCase("waiting")) {
			slapReadiness(false, command.getChannel(), command.get(2).toLowerCase());
		 } else if (command.get(1).equalsIgnoreCase("readiness") && Readiness.isReadinessType(command.get(2).toLowerCase())
			   && command.get(3).equalsIgnoreCase("done")) {
			slapReadiness(true, command.getChannel(), command.get(2).toLowerCase());
		 } else if (command.get(1).equalsIgnoreCase("readiness") && Readiness.isReadinessType(command.get(2).toLowerCase())
			   && command.get(3).equalsIgnoreCase("unregistered")) {
			slapReadinessUnregistered(command.getChannel(), command.get(2).toLowerCase());
		 }
	  } else if (command.size() == 5) {
		 if (command.get(1).equalsIgnoreCase("event") && command.isInt(2) && command.get(3).equalsIgnoreCase("not")
			   && command.get(4).equalsIgnoreCase("attending")) {
			slapEvent("not attending", getEventID(Integer.parseInt(command.get(2))), command.getChannel());
		 }
	  }
   }

   public void handleUnclaim(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1)
		 if (ClaimedTarget.deleteFromDB(UserCentral.getInstance().getOnlineUser(command.getSender()))) {
			out.addOutput("Target unclaimed");
		 }
   }

   public void handleWave(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 2) {
		 if (command.get(1).equalsIgnoreCase("attending"))
			if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), "attending", "")) {
			   out.addOutput("Attendance info set");
			}
	  } else if (command.size() == 3) {
		 if (command.get(1).equalsIgnoreCase("not") && command.get(2).equalsIgnoreCase("attending")) {
			if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), "not attending", "")) {
			   out.addOutput("Attendance info set");
			}
		 } else if (command.get(1).equalsIgnoreCase("late") && command.get(2).matches("[0-9]{1,5}(m|h)"))
			if (setAttendance(UserCentral.getInstance().getOnlineUser(command.getSender()), command.get(2), "")) {
			   out.addOutput("Attendance info set");
			}
	  } else if (command.size() == 1) {
		 Event wave = Event.getWave();
		 String user = UserCentral.getInstance().getOnlineUser(command.getSender());
		 String race = CommonMethods.getRace(user);
		 String pers = CommonMethods.getPersonality(user);
		 String racepers = race + " " + pers;
		 String orders = getNewOrdersAmount(command.getSender()) > 0 ? Colors.RED + "orders ("
			   + getNewOrdersAmount(command.getSender()) + " new)" : Colors.DARK_GREEN + "orders";
		 String aid = getNewAidAmount(user) > 0 ? Colors.RED + "aid (" + getNewAidAmount(user) + " new)" : Colors.DARK_GREEN
			   + "aid";
		 String events = getNewEventsAmount(user) > 0 ? Colors.RED + "events (" + getNewEventsAmount(user) + " new)"
			   : Colors.DARK_GREEN + "events";
		 String naps = getNewNapsAmount(user) > 0 ? Colors.RED + "naps (" + getNewNapsAmount(user) + " new)" : Colors.DARK_GREEN
			   + "naps";
		 String build = getNewBuildCheck(user, racepers) ? Colors.RED + "build (new)" : Colors.DARK_GREEN + "build";
		 out.addOutput(orders + Colors.NORMAL + " | " + aid + Colors.NORMAL + " | " + Colors.BOLD + "wave" + Colors.NORMAL
			   + " | " + events + Colors.NORMAL + " | " + build + Colors.NORMAL + " | " + naps);
		 if (wave != null) {
			out.addOutput(wave.getIRCOutput(Constants.WAVE_UTO_TIME));
		 } else {
			out.addOutput("No wave is scheduled");
		 }
	  }
	  addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "wave");
   }

   public void handleWavetime(final IRCCommand command, final IRCOutput out) {
	  if (command.size() == 1) {
		 Event wave = Event.getWave();
		 if (wave != null) {
			out.addOutput(wave.getIRCOutput(Constants.WAVE_REAL_TIME,
				  CommonMethods.getUserTimeZone(UserCentral.getInstance().getOnlineUser(command.getSender()))));
		 }
	  } else if (!CommonMethods.getUserFromDBFuzzyMatching(command.get(1)).equals("")) {
		 String user = CommonMethods.getUserFromDBFuzzyMatching(command.get(1));
		 Event wave = Event.getWave();
		 if (wave != null) {
			out.addOutput(wave.getIRCOutput(Constants.WAVE_REAL_TIME, CommonMethods.getUserTimeZone(user)));
		 }
	  }
	  addUserCheck(UserCentral.getInstance().getOnlineUser(command.getSender()), "wave");
   }

   /**
    * Formats a list of claimed provinces
    * 
    * @return
    */
   private List<String> listClaimed() {
	  List<String> out = new LinkedList<String>();
	  List<ClaimedTarget> claimed = new LinkedList<ClaimedTarget>();
	  List<ClaimedTarget> hit = new LinkedList<ClaimedTarget>();
	  for (ClaimedTarget ct : ClaimedTarget.getClaimed()) {
		 if ("".equals(ct.getClaimedBy())) {
			hit.add(ct);
		 } else {
			claimed.add(ct);
		 }
	  }

	  String output = Colors.OLIVE + "Claimed provinces: ";
	  for (ClaimedTarget ct : claimed) {
		 if (output.length() > 300) {
			out.add(output);
			output = "";
		 }
		 output += ct.getIRCOutput(0).get(0) + Colors.NORMAL + ", ";
	  }
	  if (output.length() > 1) {
		 out.add(output);
	  }

	  output = Colors.DARK_GREEN + "Hit provinces: ";
	  for (ClaimedTarget ct : hit) {
		 if (output.length() > 300) {
			out.add(output);
			output = "";
		 }
		 output += ct.getIRCOutput(0).get(0) + Colors.NORMAL + ", ";
	  }
	  if (output.length() > 1) {
		 out.add(output);
	  }
	  return out;
   }

   /**
    * Fetches and formats naps, or just a specific nap
    * 
    * @param kd
    * @param full
    * @return
    */
   private List<String> listNaps(final String kd, final boolean full) {
	  List<String> out = new LinkedList<String>();
	  String output = "Current kd's: ";
	  for (Nap nap : Nap.getNaps()) {
		 if (output.length() > 350) {
			out.add(output);
			output = "";
		 }
		 output += nap.getKd()
			   + (full && nap.getEndDate() - GregorianCalendar.getInstance().getTimeInMillis() < 365 * 24 * 3600 * 1000 ? " ends "
					 + new UtopiaTime(nap.getEndDate()).formattedUT()
					 : "") + ", ";
	  }
	  if (output.length() > 2) {
		 out.add(output.substring(0, output.length() - 2));
	  }
	  return out;
   }

   private List<String> listOrderCategories() {
	  List<String> out = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM ordercategory");
		 rs = ps.executeQuery();

		 StringBuilder output = new StringBuilder(100);
		 while (rs.next()) {
			if (output.length() > 350) {
			   out.add(output.toString());
			   output = new StringBuilder(100);
			}
			output.append(rs.getString("category") + ", ");
		 }
		 if (output.length() > 0) {
			out.add(output.toString());
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Fetches and formats orders. Users can only see the orders targetted at them, unless they're admin
    * 
    * @param sender
    * @param onlyNewOrders
    * @return
    */
   private static List<String> listOrders(final String sender, final boolean onlyNewOrders, final boolean addCheck) {
	  List<String> out = new LinkedList<String>();
	  String user = UserCentral.getInstance().getOnlineUser(sender);
	  boolean isAdmin = UserCentral.getInstance().onlineUserIsAdmin(sender, "-");
	  String race = CommonMethods.getRace(user);
	  String pers = CommonMethods.getPersonality(user);
	  String racepers = race + " " + pers;
	  String aid = getNewAidAmount(user) > 0 ? Colors.RED + "aid (" + getNewAidAmount(user) + " new)" : Colors.DARK_GREEN + "aid";
	  String events = getNewEventsAmount(user) > 0 ? Colors.RED + "events (" + getNewEventsAmount(user) + " new)"
			: Colors.DARK_GREEN + "events";
	  String naps = getNewNapsAmount(user) > 0 ? Colors.RED + "naps (" + getNewNapsAmount(user) + " new)" : Colors.DARK_GREEN
			+ "naps";
	  String build = getNewBuildCheck(user, racepers) ? Colors.RED + "build (new)" : Colors.DARK_GREEN + "build";
	  String wave = getNewWaveCheck(user) ? Colors.RED + "wave (new)" : Colors.DARK_GREEN + "wave";
	  out.add(Colors.BOLD + "orders" + Colors.NORMAL + " | " + aid + Colors.NORMAL + " | " + wave + Colors.NORMAL + " | "
			+ events + Colors.NORMAL + " | " + build + Colors.NORMAL + " | " + naps);
	  List<Order> orders = new LinkedList<Order>();
	  if (onlyNewOrders) {
		 Long lastCheck = getUserCheck(user, "orders");
		 for (Order order : Order.getOrders()) {
			if (order.getTime() > lastCheck) {
			   orders.add(order);
			}
		 }
	  } else {
		 orders = Order.getOrders();
	  }

	  int counter = 1;
	  for (Order order : orders) {
		 if (order.getOrderTo().equals(user) || order.getOrderTo().equals(race) || order.getOrderTo().equals(racepers)
			   || order.getOrderTo().equals(pers) || isAdmin || order.getOrderTo().equals("")) {

			out.addAll(order.getIRCOutput(onlyNewOrders ? Constants.ORDERS_NEW_ONLY : Constants.ORDERS_FULL,
				  CommonMethods.getUserTimeZone(user), String.valueOf(counter)));
			++counter;
		 }
	  }
	  if (addCheck)
		 addUserCheck(user, "orders");
	  return out;
   }

   /**
    * Highlights everyone in the specified channel
    * 
    * @param channel
    */
   private void slapAll(final String channel) {
	  String slap = "slaps ";
	  List<String> users;
	  if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
		 users = UserCentral.getInstance().getMainchanUsers();
	  } else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
		 users = UserCentral.getInstance().getAdminchanUsers();
	  } else
		 return;
	  for (String s : users) {
		 for (String nick : UserCentral.getInstance().getCurrentNicks(s)) {
			slap += nick + " ";
		 }
		 if (slap.length() > 300) {
			Bot.getInstance().sendAction(channel, slap);
			slap = "slaps ";
		 }
	  }
	  if (!"slaps ".equals(slap)) {
		 Bot.getInstance().sendAction(channel, slap);
	  }
   }

   /**
    * Highlights users with their armies home
    * 
    * @param channel
    */
   private void slapArmiesHome(final String channel) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory
			   .getConnectionHandler()
			   .getConnection()
			   .prepareStatement(
					 "SELECT * FROM " + "kdprovince WHERE NOT EXISTS"
						   + "(SELECT * FROM army WHERE army.mainnick = kdprovince.mainnick)");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Highlights users that have not yet registered attendance for the specified event
    * 
    * @param description
    * @param channel
    */
   private void slapEventUnregistered(final String description, final String channel) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kdprovince");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM attendance WHERE eventdescription = ?");
		 ps.setString(1, description);
		 rs = ps.executeQuery();

		 while (rs.next()) {
			for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
			   users.remove(s);
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Highlights all users in the specified channels that are registered to a province
    * 
    * @param channel
    */
   private void slapKD(final String channel) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kdprovince");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Highlights users based on their race/pers
    * 
    * @param channel
    * @param racepers
    */
   private void slapRacePers(final String channel, final String racepers) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory
			   .getConnectionHandler()
			   .getConnection()
			   .prepareStatement(
					 "SELECT * FROM kdprovince,province WHERE "
						   + "province.name = kdprovince.province AND (race = ? OR personality = ?)");
		 ps.setString(1, racepers);
		 ps.setString(2, racepers);
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Highlights users based on their readiness status for a specified readiness type
    * 
    * @param slapDone
    * @param channel
    * @param type
    */
   private void slapReadiness(final boolean slapDone, final String channel, final String type) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "readiness WHERE done = ? AND readinesstype = ?");
		 ps.setBoolean(1, slapDone);
		 ps.setString(2, type);
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(rs.getString("mainnick"));
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(rs.getString("mainnick"));
				  }
			   }
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Highlights users that have not registered their readiness status
    * 
    * @param channel
    * @param type
    */
   private void slapReadinessUnregistered(final String channel, final String type) {
	  final LinkedList<String> users = new LinkedList<String>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kdprovince");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			if (channel.equalsIgnoreCase(Main.getBotSettings().getMainChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getMainchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			} else if (channel.equalsIgnoreCase(Main.getBotSettings().getAdminChannel())) {
			   for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
				  if (UserCentral.getInstance().getAdminchanUsers().contains(s)) {
					 users.add(s);
				  }
			   }
			}
		 }

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM readiness WHERE readinesstype = ?");
		 ps.setString(1, type);
		 rs = ps.executeQuery();

		 while (rs.next()) {
			for (String s : UserCentral.getInstance().getCurrentNicks(rs.getString("mainnick"))) {
			   users.remove(s);
			}
		 }

		 String slap = "slaps ";
		 for (String s : users) {
			slap += s + " ";
			if (slap.length() > 300) {
			   Bot.getInstance().sendAction(channel, slap);
			   slap = "slaps ";
			}
		 }
		 if (!"slaps ".equals(slap)) {
			Bot.getInstance().sendAction(channel, slap);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
   }

   /**
    * Starts a readiness type
    * 
    * @param type
    * @param autoPopulate
    * @return
    */
   public boolean startReadiness(final String type, final boolean autoPopulate) {
	  boolean out = false;
	  if (!Readiness.isReadinessType(type))
		 return out;
	  resetReadiness(type);
	  if (autoPopulate) {
		 PreparedStatement ps = null;
		 ResultSet rs = null;
		 try {
			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kdprovince");
			rs = ps.executeQuery();

			final LinkedList<String> users = new LinkedList<String>();
			while (rs.next()) {
			   users.add(rs.getString("mainnick"));
			}

			for (String s : users) {
			   ps = DBConnectionFactory.getConnectionHandler().getConnection()
					 .prepareStatement("INSERT INTO readiness VALUES(?,false,?)");
			   ps.setString(1, s);
			   ps.setString(2, type);
			   ps.executeUpdate();
			}
			out = true;
		 } catch (final SQLException e) {
			Logger.getLogger("Error").error("", e);
		 } finally {
			try {
			   rs.close();
			} catch (final Exception e) {
			}
			try {
			   ps.close();
			} catch (final Exception e) {
			}
		 }
	  }
	  setReadinessActivity(type, true);
	  out = true;
	  return out;
   }

   /**
    * Checks what the user needs to build to match the specified build and returns what to build/raze
    * 
    * @param user
    * @param type
    * @return
    */
   private List<String> toBuild(final String user, final String type) {
	  List<String> out = new LinkedList<String>();
	  String race = CommonMethods.getRace(user);
	  String personality = CommonMethods.getPersonality(user);

	  Build build = Build.getBuild(race, personality, type);
	  Province prov = Province.getInternalProvince(user);
	  Survey survey = prov == null ? null : prov.getSurvey();

	  Map<String, Double> toBuild = new HashMap<String, Double>();
	  Map<String, Double> percentages = new HashMap<String, Double>();
	  if (build != null && survey != null) {
		 for (Entry<String, String> e : build.getBuildings().entrySet()) {
			toBuild.put(
				  e.getKey(),
				  Double.parseDouble(e.getValue()) / 100 * survey.getLand()
						- survey.getBuilding(CommonMethods.getBuildingsMapping(e.getKey()))
						- survey.getBuildingInProgress(CommonMethods.getBuildingsMapping(e.getKey())));
			percentages.put(e.getKey(), Double.parseDouble(e.getValue()));
		 }

		 for (Entry<String, Building> e : UtopiaHandler.loadBuildings().entrySet()) {
			if (survey.getBuilding(CommonMethods.getBuildingsMapping(e.getKey())) > 0 && !toBuild.containsKey(e.getKey())) {
			   toBuild.put(e.getKey(),
					 Double.parseDouble(String.valueOf(0 - survey.getBuilding(CommonMethods.getBuildingsMapping(e.getKey())))));
			   percentages.put(e.getKey(), 0.0);
			}
		 }

		 String output = Colors.BLUE + survey.getName() + ": ";
		 for (Entry<String, Double> e : toBuild.entrySet()) {
			if (output.length() > 350) {
			   out.add(output);
			   output = "";
			}
			output += Colors.OLIVE + e.getKey() + Colors.NORMAL + " (" + percentages.get(e.getKey()) + "%) " + Colors.BLUE
				  + e.getValue().intValue() + Colors.NORMAL + " <> ";
		 }
		 if (output.length() > 0) {
			out.add(output);
		 }
	  }
	  return out;
   }
}
